#include "selectserver.h"
#include <stdbool.h>
#include <windows.h>
#include <stdio.h>
#include "socketlibfunction.h"
#include "platform.h"

void logic_on_enter_pt_my(struct server_s* self, int index)
{
	printf("one client, index is %d enter\n", index);
}


void logic_on_close_pt_my(struct server_s* self, int index)
{
	printf("one client close, index is %d\n", index);
    server_socket_close(self, index);
}

#define SOCKETSEND(SERVER, INDEX, DATA) server_socket_send(SERVER, INDEX, DATA, strlen(DATA))

static void cannot_do(struct server_s* self, int index)
{
    SOCKETSEND(self,index, "HTTP/1.0 501 Not Implemented\r\n");
    SOCKETSEND(self,index, "Content-type:text/plain\r\n");
    SOCKETSEND(self,index, "\r\n");
    SOCKETSEND(self,index, "That command is not yet implemented\r\n");
}

static void do_404(struct server_s* self, int index, const char* file)
{
    SOCKETSEND(self,index, "HTTP/1.0 404 Not Found\r\n");
    SOCKETSEND(self,index, "Content-type:text/plain\r\n");
    SOCKETSEND(self,index, "\r\n");
    SOCKETSEND(self,index, "The item you requested:");
    SOCKETSEND(self,index, file);
    SOCKETSEND(self,index, "\r\nis not found\r\n");
}

static FILE *fp = NULL;

#include <stdio.h>

char* load_file( const char *filename, int* outlen)
{
    char* buffer = NULL;
    int file_size = 0;

    if(NULL == fp)
    {
        fopen(filename, "rb");
        if(0 == fp)
        {
            return NULL;
        }
    }

    fseek( fp, 0, SEEK_END );
    file_size = ftell( fp );
    fseek( fp, 0, SEEK_SET );

    buffer = (char*) malloc(file_size + 1);
    fread(buffer, file_size, 1, fp);
    buffer[file_size] = 0;
    fclose( fp );

    if(NULL != outlen)
    {
        *outlen = file_size;
    }

    return buffer;
}

static bool not_exist(const char* filename)
{
#ifdef PLATFORM_WINDOWS
    fp = fopen(filename, "rb");
    return (NULL == fp);
#else
    struct stat info;
    return (stat(filename, &info) == -1);
#endif
}

const char* file_type(const char* filename)
{
    const char* cp;
    if ((cp = strrchr(filename, '.')) != NULL)
    {
        return cp+1;
    }

    return "";
}

static void do_cat(struct server_s* self, int index, const char* file)
{
    int len = 0;
    const char* filedata = NULL;
    const char* extension = file_type(file);
    const char* content = "text/plain";

    if (strcmp(extension, "html") == 0 || strcmp(extension, "htm") ==0 || strcmp(extension, "txt") == 0)
    {
        content = "text/html";
    }
    else if(strcmp(extension, "gif") == 0)
    {
        content = "image/gif";
    }
    else if(strcmp(extension, "png") == 0)
    {
        content = "image/png";
    }
    else if (strcmp(extension, "jpg") == 0 || strcmp(extension, "jpeg") == 0)
    {
        content = "image/jpeg";
    }

    filedata = load_file(file, &len);

    if (NULL != filedata)
    {
        SOCKETSEND(self,index, "HTTP/1.0 200 OK\r\n");
        SOCKETSEND(self,index, "Content-type:");
        SOCKETSEND(self,index, content);
        SOCKETSEND(self,index, "\r\n");

        SOCKETSEND(self,index, "\r\n");
        server_socket_send(self, index, filedata, len);
        free((void*)filedata);
        filedata = NULL;
    }
    else
    {
        do_404(self, index, file);
    }
}

static void process_http(struct server_s* self, int index, const char* httpRequest, int len)
{
    char cmd[1024], arg[1024];
    arg[0] = cmd[0] = 0;

#ifdef PLATFORM_WINDOWS
    strcpy((char*)arg, ".");
    if (sscanf(httpRequest, "%s%s", cmd, arg+1) != 2)
    {
        return;
    }
#else
    strcpy((char*)arg, "./");
    if (sscanf(httpRequest, "%s%s", cmd, arg+2) != 2)
    {
        return;
    }
#endif

    if (strcmp(cmd, "GET") != 0)
    {
        cannot_do(self, index);
    }
    else if (not_exist(arg))
    {
        do_404(self, index, arg);
    }
    else
    {
        do_cat(self, index, arg);
    }
}

int logic_on_recved_pt_my(struct server_s* self, int index, const char* buffer, int len)
{
    if(strstr(buffer, "\r\n\r\n"))
    {
        process_http(self, index, buffer, len);
        server_socket_close(self, index);
    }

    return 0;
}

static DWORD accept_thread(LPVOID arg)
{
    sock fd = socket_listen(5000, 10);
	struct server_s* server = (struct server_s*)arg;
    sock s = SOCKET_ERROR;
    struct sockaddr_in socketaddress;
    socklen_t size = sizeof(struct sockaddr);

	if(SOCKET_ERROR != fd)
	{
		printf("start listen...\n");

        while(true)
        {
            while((s = accept( fd, (struct sockaddr*)&socketaddress, &size)) < 0)
            {
                if(EINTR == sErrno)
                {
                    continue;
                }
            }

            if(s != SOCKET_ERROR)
            {
                server_socket_add(server, s);
            }
        }
	}

	if(SOCKET_ERROR != fd)
	{
		socket_close(fd);
		fd = SOCKET_ERROR;
	}

	printf("end listen...\n");
    return 0;
}

int main()
{
    struct server_s* server = NULL;
    HANDLE h;
    DWORD thread_id;
	socket_init();
	server = selectserver_new(10, logic_on_enter_pt_my, logic_on_close_pt_my, logic_on_recved_pt_my, 1024, 1024);
	
    h = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)accept_thread, server, 0, (PDWORD)&thread_id);

	while(1)
	{
        Sleep(1);
		server_poll(server);
	}
	return 0;
}
